﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BadmintonBuddy.Models;
using BadmintonBuddy.Helpers;
using System.Configuration;
using System.Web.UI;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Dynamic;
using Facebook.Web;
using Facebook.Web.Mvc;

namespace BadmintonBuddy.Controllers
{
    public class ClubController : Controller
    {
        ClubRepository repository = new ClubRepository();        
        
        [OutputCache(Duration = int.MaxValue, VaryByParam = "none",Location=OutputCacheLocation.ServerAndClient)]
        public ActionResult Index()
        {
            try
            {
                var clubs = repository.GetAllClubs("Name");
                return View(clubs);
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
                return View("Clubs");
            }
        }

        public ActionResult IndexN()
        {            
            IQueryable<Club> clubs = repository.GetAllNonApprovedClubs();
            return View("Index",clubs);
        }

        [OutputCache(Duration = int.MaxValue, VaryByParam = "none", Location = OutputCacheLocation.ServerAndClient)]
        public ActionResult About()
        {
            return View();
        }

        [HttpGet]        
        public ActionResult Edit(int id)
        {
            try
            {
                Club club = repository.SearchClubById(id);
                return View("Edit", club);
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex,"ClubId :"+id.ToString());
                return View("Clubs");
            }

        }

        [HttpPost]
        public ActionResult Edit(int id,FormCollection formValues)
        {
            try
            {
                Club club = repository.SearchClubById(id);
                if (ModelState.IsValid)
                {
                    UpdateModel(club);
                    repository.Save();
                }
                return RedirectToAction("Details", new { clubname = club.ClubName });
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
                return View("Clubs");
            }
        }

        [OutputCache(Duration = int.MaxValue, VaryByParam = "none", Location = OutputCacheLocation.ServerAndClient)]
        public ActionResult Clubs()
        {   
            return View();
        }

        [ChildActionOnly]
        public ActionResult TagCloud()
        {
            return PartialView();

        }

        [OutputCache(Duration=int.MaxValue,VaryByParam="latWest;latEast;lngWest,lngEast",Location=OutputCacheLocation.ServerAndClient)] 
        public JsonResult ClubsByRegion(float latWest, float latEast, float lngWest, float lngEast)
        {
            try
            {
                BadmintonBuddy.Models.Region region = SetRegion(latWest, latEast, lngWest, lngEast);
                var clubs = repository.GetClubsByRegion(region);

                return Json(clubs.ToList());
            }
            catch(Exception ex)
            {
                Log.WriteException(repository, ex);
                return Json(ex.Message);
            }
        }

        [OutputCache(Duration = int.MaxValue, VaryByParam = "sortby", Location = OutputCacheLocation.ServerAndClient)]
        public JsonResult SortData(string sortby)
        {
            try
            {
                var details = repository.GetAllClubs(sortby);
                return Json(details.ToList());
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
                return Json(ex.Message);
            }
        }

        public ActionResult Reroute(string url)
        {
            return Reroute(url);
        }

        private BadmintonBuddy.Models.Region SetRegion(float latWest, float latEast, float lngWest, float lngEast)
        {
            BadmintonBuddy.Models.Region region = new BadmintonBuddy.Models.Region();
            region.WestLatitude = latWest;
            region.WestLongitude = lngWest;
            region.EastLatitude = latEast;
            region.EastLongitude = lngEast;
            return region;
        }       

        [HttpPost]
        public ActionResult Feedback(FormCollection feedbackCol)
        {
            try
            {
                StringBuilder builder = new StringBuilder();
                builder.Append("<root>");
                builder.Append("<feedbacktype>");
                builder.Append(feedbackCol.Get("feedbacktype"));
                builder.Append("</feedbacktype>");
                builder.Append("<description>");
                builder.Append(feedbackCol.Get("desc"));
                builder.Append("</description>");
                builder.Append("<email>");
                builder.Append(feedbackCol.Get("email"));
                builder.Append("</email>");
                builder.Append("</root>");
                Log.WriteLog(repository, LogType.Feedback, builder.ToString());

                ViewData["Confirmation"] = "Thanks for submitting your Feedback. We will look into it.!!";
                return View("Confirmation");
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
                return View("Clubs");
            }
        }

        [HttpGet]
        [OutputCache(Duration = int.MaxValue, VaryByParam = "none", Location = OutputCacheLocation.ServerAndClient)]
        public ActionResult Feedback()
        {
            return View();
        }

        public void ReportProblem(string clubId, string problem)
        {
            try
            {
                StringBuilder builder = new StringBuilder();
                builder.Append("<root>");
                builder.Append("<clubid>");
                builder.Append(clubId);
                builder.Append("</clubid>");
                builder.Append("<problem>");
                builder.Append(problem);
                builder.Append("</problem>");
                builder.Append("</root>");
                Log.WriteLog(repository, LogType.ReportProblem, builder.ToString());
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);             
            }

        }

        [OutputCache(Duration = int.MaxValue, VaryByParam = "term", Location = OutputCacheLocation.ServerAndClient)]
        public JsonResult Suggest(string term)
        {
            try
            {
                return Json(repository.AutoSuggest(term).ToList(), JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
                return Json(ex.Message);
            }
        }       

        
        
        [OutputCache(Duration = int.MaxValue, VaryByParam = "q;filter", Location = OutputCacheLocation.ServerAndClient)]
        public ActionResult Search(string q, string filter)
        {
            try
            {
                var clubs = from c in repository.SearchClub(q, filter)
                            select c;
                ViewData["q"] = q.Trim();
                return View(clubs);
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex,"searchquery :"+q);
                return View("Clubs");
            }
        }

        [HttpGet]
        [OutputCache(Duration = int.MaxValue, VaryByParam = "none", Location = OutputCacheLocation.ServerAndClient)]
        public ViewResult Create()
        {
            Club club = new Club();            
            return View(club);
        }

        
        [HttpPost]
        public ActionResult Create(FormCollection collection)
        {
            try
            {
                int newClubID = repository.Save(collection, false);
                ViewData["ClubID"] = newClubID;
                ViewData["Confirmation"] = "Thanks for submitting the Club Details. Your entry will be verified and added as soon as possible!!";
                return View("Confirmation");
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
                return View("Clubs");
            }
            
        }

        [HttpGet]

        [OutputCache(Duration = int.MaxValue, VaryByParam = "none", Location = OutputCacheLocation.ServerAndClient)]
        public ViewResult AddClubsHere()
        {
            return View();
        }

        [HttpPost]
        public ActionResult AddClubsHere(FormCollection clubDetails)
        {
            repository.Save(clubDetails,true);
            return View();
        }

        public ActionResult Confirmation()
        {            
            return View();
        }


        [OutputCache(Duration = int.MaxValue, VaryByParam = "clubname", Location = OutputCacheLocation.ServerAndClient)]
        public ViewResult Badminton(string clubname)
        {
            //Use this for just providing link so that search engines can identify.
            //Add to sitemap.
            var clubList = from club in repository.GetClubsByLocation(clubname)
                           select club;
            ViewData["Location"] = clubList.First<Club>().City.CityName;
            return View(clubList);
        }


        [HttpPost]
        public ActionResult Add(Club club)
        {
            if (ModelState.IsValid)
            {
                repository.Add(club);
                //repository.Save();                
            }

            string clubName = club.ClubName;
            FormCollection collection = new FormCollection();            
            return View(new ClubFormViewModel(new Club()));
        }

        [OutputCache(Duration = int.MaxValue, VaryByParam = "clubname", Location = OutputCacheLocation.ServerAndClient)]
        public ViewResult Details(string clubname)
        {
            try
            {
                string club_name = clubname.Replace("-", " ");
                if (!String.IsNullOrEmpty(club_name))
                {
                    var clubDetail = repository.GetClubDetails(club_name);
                    Club firstClub = clubDetail.First<Club>();
                    string location = firstClub.City.CityName;
                    int excludeId = firstClub.ClubID;
                    var relatedClubs = repository.GetClubsByLocation(location, excludeId);
                    List<Club> clubList = new List<Club>();
                    clubList.Add(clubDetail.First<Club>());
                    clubList.AddRange(relatedClubs);
                    return View(clubList);
                }
                else
                {
                    ViewData["Message"] = "Please add proper details";
                    return View("Message");
                }
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex,"clubName:"+clubname);
                return View("Clubs");
            }
        }

        
        public JsonResult GetCountry(string term)
        {
            try
            {
                return Json(repository.GetCountry(term), JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
                return Json(ex.Message);
            }
        }

        
        public JsonResult GetState(string term,string country)
        {
            try
            {
                return Json(repository.GetState(term, country), JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
                return Json(ex.Message);
            }
        }

        
        public JsonResult GetCity(string term,string state)
        {
            try
            {
                return Json(repository.GetCity(term, state), JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
                return Json(ex.Message);
            }
        }

        public ActionResult LogList()
        {
            IQueryable<LogDetail> detailList = repository.GetLogs();
            return View(detailList);
        }

        #region Captcha

        private const int ImageWidth = 200, ImageHeight = 70;
        private const string FontFamily = "Arial";
        private readonly static Brush Foreground = Brushes.Navy;
        private readonly static Color Background = Color.Silver;

        private const int WarpFactor = 5;
        private const Double xAmp = WarpFactor * ImageWidth / 100;
        private const Double yAmp = WarpFactor * ImageHeight / 85;
        private const Double xFreq = 2 * Math.PI / ImageWidth;
        private const Double yFreq = 2 * Math.PI / ImageHeight;

        public void Render(string solution)
        {
            if (solution != null)
            {
                // Make a blank canvas to render the CAPTCHA on
                using (Bitmap bmp = new Bitmap(ImageWidth, ImageHeight))
                using (Graphics g = Graphics.FromImage(bmp))
                using (Font font = new Font(FontFamily, 1f))
                {
                    g.Clear(Background);

                    // Perform trial rendering to determine best font size
                    SizeF finalSize;
                    SizeF testSize = g.MeasureString(solution, font);
                    float bestFontSize = Math.Min(ImageWidth / testSize.Width,
                                            ImageHeight / testSize.Height) * 0.95f;

                    using (Font finalFont = new Font(FontFamily, bestFontSize))
                    {
                        finalSize = g.MeasureString(solution, finalFont);
                    }

                    // Get a path representing the text centered on the canvas
                    g.PageUnit = GraphicsUnit.Point;
                    PointF textTopLeft = new PointF((ImageWidth - finalSize.Width) / 2,
                                                  (ImageHeight - finalSize.Height) / 2);
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        path.AddString(solution, new FontFamily(FontFamily), 0,
                            bestFontSize, textTopLeft, StringFormat.GenericDefault);

                        // Render the path to the bitmap
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.FillPath(Foreground, DeformPath(path));
                        g.Flush();

                        // Send the image to the response stream in PNG format
                        Response.ContentType = "image/png";
                        using (var memoryStream = new MemoryStream())
                        {
                            bmp.Save(memoryStream, ImageFormat.Png);
                            memoryStream.WriteTo(Response.OutputStream);
                        }
                    }
                }
            }
        }

        private GraphicsPath DeformPath(GraphicsPath path)
        {
            PointF[] deformed = new PointF[path.PathPoints.Length];
            Random rng = new Random();
            Double xSeed = rng.NextDouble() * 2 * Math.PI;
            Double ySeed = rng.NextDouble() * 2 * Math.PI;
            for (int i = 0; i < path.PathPoints.Length; i++)
            {
                PointF original = path.PathPoints[i];
                Double val = xFreq * original.X + yFreq * original.Y;
                int xOffset = (int)(xAmp * Math.Sin(val + xSeed));
                int yOffset = (int)(yAmp * Math.Sin(val + ySeed));
                deformed[i] = new PointF(original.X + xOffset, original.Y + yOffset);
            }
            return new GraphicsPath(deformed, path.PathTypes);
        }      

        #endregion Captcha

        #region Facebook

        public ActionResult SignUp()
        {
            return View();
        }
        public ActionResult Facebook()
        {
            return View();
        }

        [FacebookAuthorize]
        public void UserProfile(string userId)
        {
            try
            {
                var app = new FacebookWebClient();
                dynamic me = app.Get("me");
                Models.User user;
                IQueryable<User> userList = repository.GetUser(userId);
                if (userList.Count() == 0)
                {
                    user = new User();
                    user.UserID = me.id;
                    user.UserName = me.username;
                    user.FirstName = me.first_name;
                    user.LastName = me.last_name;
                    user.Gender = me.gender;
                    user.DateJoined = DateTime.Now;
                    user.LastLogin = DateTime.Now;
                    user.Email = me.email;
                    repository.InsertUser(user);
                }
                else
                {
                    user = userList.Single();
                    user.LastLogin = DateTime.Now;
                    repository.Save();
                }
            }
            catch (Exception ex)
            {
                Log.WriteException(repository, ex);
            }
        }

        [FacebookAuthorize]
        public ActionResult FacebookLogged()
        {
            var app = new FacebookWebClient();

            dynamic me = app.Get("me");
            dynamic friends = app.Get("/me/friends");

            dynamic model = new ExpandoObject();
            model.Name = me.name;
            model.Id = me.id;
            model.UserName = me.username;
            model.FriendCount = friends.data.Count;

            return View(model);            
        }
        #endregion Facebook



    }
}
